/*
 * Copyright (c) 2011 Ondrej Lapacek
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

/**
 * @author      Ondrej Lapacek
 * @version     1.0, 09/12/11
 * @since       1.0
 */

package cz.muni.fi.android.assistivecamera.intersectiondetector;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import android.graphics.PointF;
import android.location.Location;
import cz.muni.fi.android.assistivecamera.osm.model.OsmData;
import cz.muni.fi.android.assistivecamera.osm.model.Way;

public class IntersectionDetector {

	private static final int ACCURACY = 111319;
	private static final double DISTANCE = 0.002; // distance 222 meters

	public OsmData intersection(OsmData osmData, Location tempLocation, float azimuth, float viewAngle) { 
		
		Map<Long, Way> ways = new TreeMap<Long, Way>();
		IntersectionDetectorGeometry geom = new IntersectionDetectorGeometry();
		Map<Long, Long> counter = new HashMap<Long, Long>();
		long cnt = 0;
		
		for (float i = (azimuth-viewAngle/2); i <= (azimuth+viewAngle/2); i += 1){
			float min = 111319;
			long visibleWayKey = -1;
			
			PointF startPoint = new PointF((float)tempLocation.getLongitude(), (float)tempLocation.getLatitude());
			PointF endPoint = new PointF();
			endPoint.x = (float) (startPoint.x + DISTANCE * Math.sin(i * Math.PI / 180));
			endPoint.y = (float) (startPoint.y + DISTANCE * Math.cos(i * Math.PI / 180));

		   	Iterator<Entry<Long, Way>> wayIterator = osmData.getWays().entrySet().iterator();
		    
		   	while (wayIterator.hasNext()) {
			    Map.Entry<Long, Way> wayRecord = (Map.Entry<Long, Way>)wayIterator.next();
			        	
			    for (int j = 0; j < wayRecord.getValue().getNodeList().size()-1; j++){
			        PointF startBuildingPoint = 
			        	new PointF((float)wayRecord.getValue().getNodeList().get(j).getLocation().getLongitude(),
			        			(float)wayRecord.getValue().getNodeList().get(j).getLocation().getLatitude());
			        PointF endBuildingPoint = 
			        	new PointF((float)wayRecord.getValue().getNodeList().get(j+1).getLocation().getLongitude(),
			        			(float)wayRecord.getValue().getNodeList().get(j+1).getLocation().getLatitude());
			        		
			        PointF point = geom.findIntersection(startPoint, endPoint, startBuildingPoint, endBuildingPoint);
					if (point != null) {
						if (min > geom.pointDistance(point, new PointF(startPoint.x,startPoint.y))) {
							min = (float) geom.pointDistance(point, new PointF(startPoint.x,startPoint.y));
							visibleWayKey = (Long)wayRecord.getKey();
						}
					}
			    }
		   	}
		   	if (visibleWayKey != -1) {
		   		if (counter.get(visibleWayKey) != null) {
		   			cnt = counter.get(visibleWayKey);
		   		} else {
		   			counter.put(visibleWayKey, ++cnt);
		   		}
		   		
		   		ways.put(cnt, osmData.getWays().get(visibleWayKey));
		   		BigDecimal bd = new BigDecimal(min).setScale(6, RoundingMode.HALF_EVEN);
		   		min = (float) bd.doubleValue();
		   		min = min * ACCURACY;
		   		int minDistance = (int) min;
		   		
		   		if (ways.get(cnt).getTag("distance") != null) {
		   			if (Integer.valueOf(ways.get(cnt).getTag("distance")) > minDistance) 
		   				ways.get(cnt).setTag("distance", Integer.toString(minDistance));
		   		} else {
		   			ways.get(cnt).setTag("distance", Integer.toString(minDistance));
		   		}
		   	}
		}
		
		return new OsmData(null, ways, null);
	}
}
